package cbbx_sm.evaluation;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.List;
import java.util.Set;
import java.util.Vector;

import cbbx_sm.decision_maker.DecisionMakerFactory;
import cbbx_sm.decision_maker.IDecisionMaker;
import cbbx_sm.decision_maker.search.DynamicProgrammingTableEntry;
import cbbx_sm.decision_maker.search.States;
import cbbx_sm.parser.BoundingBox;
import cbbx_sm.parser.CameraData;
import cbbx_sm.parser.Entity;
import cbbx_sm.parser.Frame;
import cbbx_sm.parser.Parser;
import cbbx_sm.probabilistic_model.Cluster;
import cbbx_sm.probabilistic_model.Clustering;
import cbbx_sm.probabilistic_model.IPredictor;
import cbbx_sm.probabilistic_model.NoisyOrPredictor;
import cbbx_sm.probabilistic_model.ProbabilisticModel;
import cbbx_sm.probabilistic_model.SystemShortTermMemory;
import cbbx_sm.simulation.Scheduler;
import cbbx_sm.utils.LookaheadPredictorSerializator;
import cbbx_sm.utils.Utility;

public class MostLikelyClusterZoom {
	public static void main(String[] args) throws IOException, InterruptedException{
		// Cameras scheduled.
		ArrayList<String> cameraIds = new ArrayList<String>();
		cameraIds.add("cam16");
		cameraIds.add("cam17");
		cameraIds.add("cam18");
		
		// Camera Data.
		Hashtable<String, CameraData> cameraData = new Hashtable<String, CameraData>();
		ArrayList<CameraData> cameraDataList = new ArrayList<CameraData>();
		for (String cam: cameraIds){
			CameraData data = Parser.parseFile("data/cameraData/20090527"+cam.substring(3)+".txt", cam);
			cameraData.put(cam, data);
			cameraDataList.add(data);
		}		

		// Number of Clusters.
		int k=4;
		
		// Each camera has a cluster.
		Hashtable<String, List<Cluster>> camClusters = new Hashtable<String, List<Cluster>>();
		for (String cam: cameraIds){
			System.out.println("Clustering cam "+cam+"...");
			Set<BoundingBox> boxes = new HashSet<BoundingBox>();
			for (Frame f : cameraData.get(cam).getFrames())
				for(Entity e : f.getEntities())
					boxes.add(e.getBoxes()[1]);
			
			
			List<Cluster> clusters = Clustering.kMeansClustering(cameraData.get(cam), k);
			
			camClusters.put(cam, clusters);
		}
		
		// All the clusters together.
		List<Cluster> fusedClusters = new Vector<Cluster>();
		for (String cam: cameraIds){
			fusedClusters.addAll(camClusters.get(cam));
		}

		// Load the probabilistic model or create it.
		ProbabilisticModel probModel = ProbabilisticModel.readUp("model16_17_18kmeans.ser");

		if (probModel == null){
			probModel = new ProbabilisticModel(cameraDataList, fusedClusters, cameraDataList.get(0).getFinalTimestamp()-cameraDataList.get(0).getInitialTimestamp());
			probModel.setThreshold(0.0);
			ProbabilisticModel.writeDown(probModel, "model16_17_18kmeans.ser");
			
			System.out.println("Probabilities computed.");
			System.out.println(probModel.toString());
		}
		
		
		// Load the test dataset.
		cameraData = new Hashtable<String, CameraData>();
		cameraDataList = new ArrayList<CameraData>();
		for (String cam: cameraIds){
			CameraData data = Parser.parseFile("data/cameraData/20090528"+cam.substring(3)+".txt", cam);
			data.setImageFile("data/images/"+cam.substring(3)+".jpg");
			cameraData.put(cam, data);
			cameraDataList.add(data);
		}

		// Prepare the data structures for the scheduler simulator.
		List<List<Cluster>> clusters = new Vector<List<Cluster>>();
		for (String cam: cameraIds){
			clusters.add(camClusters.get(cam));
		}
		
		int numberOfBBoxes = 0;
		for (CameraData data: cameraDataList){
			numberOfBBoxes+=data.getNumberOfFrameWithBoundingBoxes();
		}
		System.out.println("NUMBER OF BBOX TO CATCH: " + numberOfBBoxes);
		System.out.println("Starting calculating probs...");
//		ProbabilisticModel probModel = new ProbabilisticModel();
//		probModel.computeProbabilities(cameraData, fusedClusters, (18 - 13) * 60 * 60);
		


		
		
		SystemShortTermMemory memory;
		IPredictor predictor;
		IDecisionMaker decisionMaker;
		Scheduler scheduler;
		
		scheduler = new Scheduler(cameraDataList, fusedClusters, clusters, probModel, "output/result_mostlikely_ronen.txt");

		memory = new SystemShortTermMemory(6);
		predictor = new NoisyOrPredictor(memory, probModel, 15, fusedClusters, true);
		

		
		Hashtable<String, Hashtable<Cluster, Integer>> clusterIndex = new Hashtable<String, Hashtable<Cluster, Integer>>();
		Hashtable<String, Hashtable<String, Cluster>> action2Cluster = new Hashtable<String, Hashtable<String, Cluster>>();
		Hashtable<String, States> s = new Hashtable<String, States>();
		Hashtable<String,DynamicProgrammingTableEntry[][]> table = new Hashtable<String,DynamicProgrammingTableEntry[][]>();
		
		double utilityZoom = 1;
		double utilityUP = 0;
		int numberOfTimeStampsLookAhead = 25;
		double delta = 1;

		
		
		for (String cam: cameraIds){
			Hashtable<Cluster, Integer> camClusterIndex = new Hashtable<Cluster, Integer>();
			for (int i=0; i<k; i++){
				camClusterIndex.put(camClusters.get(cam).get(i), i);
			}
			
			Hashtable<String, Cluster> camAction2Cluster = new Hashtable<String, Cluster>();
			for (int i=0; i<k; i++){
				camAction2Cluster.put("C"+i, camClusters.get(cam).get(i));
			}
			
			ArrayList<double[]> rawStates = LookaheadPredictorSerializator.readUpStates(Integer.parseInt(cam.substring(3)), k, utilityZoom, utilityUP, delta, numberOfTimeStampsLookAhead);
			States camStates = new States(rawStates);
			DynamicProgrammingTableEntry[][] camTable = LookaheadPredictorSerializator.readUpScoreArray(Integer.parseInt(cam.substring(3)), k, utilityZoom, utilityUP, delta, numberOfTimeStampsLookAhead);
			
			clusterIndex.put(cam, camClusterIndex);
			action2Cluster.put(cam, camAction2Cluster);
			s.put(cam, camStates);
			table.put(cam, camTable);
			
		}
		
		decisionMaker = DecisionMakerFactory.getMostLikelyClusterDecisionMaker();
		
		scheduler.setDecisionMaker(decisionMaker);
		scheduler.setMemory(memory);
		scheduler.setPredictor(predictor);
		scheduler.sequentialRun();
		System.gc();
				
	}
}
